package predictionEngine;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;

import java.awt.Paint;

import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.AxisSpace;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.data.xy.XYDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.PaintSample;
import org.jfree.ui.RefineryUtilities;
import org.jfree.util.PaintUtilities;
import org.jfree.util.ShapeList;
import org.jfree.util.ShapeUtilities;

/**
 * A simple demonstration application showing how to create a line chart using data from a
 * {@link CategoryDataset}.
 */
public class LineChartFactory {

    /**
     * Creates a new demo.
     *
     * @param title  the frame title.
     */
    private static LineChartFactory instance;
    private LineChartFactory() {
    }
    
    public static LineChartFactory getInstance(){
        if(instance == null)
            instance = new LineChartFactory();
        return instance;
    }
    
    
    public ChartPanel makePredictionChart(Dataset dataset, RandomForest forest){
        
        // row keys...
        final String series1 = "Real";
        final String series2 = "Predicted";

        // create the dataset...
        final DefaultCategoryDataset cSet = new DefaultCategoryDataset();
        List<double[]> instances = dataset.getInstances();
        int target = instances.get(0).length-1;
        for(int i = 0;i<instances.size();i++){
            double[] instance = instances.get(i);
            cSet.addValue(instance[target], series1, ""+i);            
            cSet.addValue(forest.execute(instance), series2, ""+i);
        }
        
        return getChart(cSet,"Forecast");
    }
    public ChartPanel makeTargetChart(Dataset train){
        
        // row keys...
        final String series1 = "Real";
        final String series2 = "Predicted";
        final String series3 = "Predicted-Test";
        // create the dataset...
        
        
        
        List<double[]> instances = train.getInstances();
        int target = instances.get(0).length-1;
        int i = 0;
        
        final DefaultCategoryDataset cSet = new DefaultCategoryDataset();
        double[][] xyPredictionTrain = new double[2][train.size()];
        
        double[] instance=null;
        for(;i<instances.size();i++){
            instance = instances.get(i);
            xyPredictionTrain[0][i]= instance[target];
            xyPredictionTrain[1][i]= i;
          //  cSet.addValue(forest.execute(instance), series3, ""+i);
        }
          
        
        DefaultXYDataset dsxy= new DefaultXYDataset();
        List<Attribute> atts = train.getAttributes();
        dsxy.addSeries(atts.get(atts.size()-1).getName(), xyPredictionTrain);
    
        return getChart(dsxy,"Dataset");
    }
    
    public ChartPanel makePredictionChart(Dataset train,Dataset test, RandomForest forest){
        
        // row keys...
        final String series1 = "Real";
        final String series2 = "Predicted";
        final String series3 = "Predicted-Test";
        // create the dataset...
        
        
        
        List<double[]> instances = train.getInstances();
        int target = instances.get(0).length-1;
        int i = 0;
        
        final DefaultCategoryDataset cSet = new DefaultCategoryDataset();
        double[][] xyTarget= new double[2][train.size()+test.size()];
        double[][] xyPredictionTrain = new double[2][train.size()];
        double[][] xyPredictionTest = new double[2][test.size()+1];
        
        double[] instance=null;
        for(;i<instances.size();i++){
            instance = instances.get(i);
            cSet.addValue(instance[target], series1, ""+i);            
            cSet.addValue(forest.execute(instance), series2, ""+i);
            xyTarget[0][i]= instance[target];
            xyTarget[1][i]= i;
            xyPredictionTrain[0][i]= forest.execute(instance);
            xyPredictionTrain[1][i]= i;
          //  cSet.addValue(forest.execute(instance), series3, ""+i);
        }
          cSet.addValue(forest.execute(instance), series3, ""+-i); //Connect train and test predictions
          xyPredictionTest[0][0]= forest.execute(instance);
          xyPredictionTest[1][0]= i-1;
          
        instances = test.getInstances();
        for(int j = 0 ;j<instances.size();j++,i++){
            instance = instances.get(j);
            cSet.addValue(instance[target], series1, ""+i);            
            cSet.addValue(forest.execute(instance), series3, ""+i);
            xyTarget[0][i]= instance[target];
            xyTarget[1][i]= i;
            xyPredictionTest[0][j+1]= forest.execute(instance);
            xyPredictionTest[1][j+1]= i;
        }
        
        DefaultXYDataset dsxy= new DefaultXYDataset();
        
        dsxy.addSeries("Target", xyTarget);
        dsxy.addSeries("Forecast-Training", xyPredictionTrain);
        dsxy.addSeries("Forecast-Test", xyPredictionTest);
   
        return getChart(dsxy,"Forecast");
    }
    
    public ChartPanel makeAttEvalChart(Dataset dataset, RandomForest forest, int attribute){
        
        // row keys...
        final String series1 = "Real";
        final String series2 = "Predicted";
        final String series3 = "Predicted-Test";
        String series4 = "No " +dataset.getAttribute(attribute).getName();


        double[][] preds= new double[2][dataset.size()];
        double[][] predEval= new double[2][dataset.size()];
        // create the dataset...
        final DefaultCategoryDataset cSet = new DefaultCategoryDataset();
        List<double[]> instances = dataset.getInstances();
        int target = instances.get(0).length-1;
        double[] instance = instances.get(0).clone();
        cSet.addValue(0, series1, ""+0);
        cSet.addValue(forest.execute(instance), series2, ""+0);
        cSet.addValue(0, series3, ""+0);
        preds[0][0]=forest.execute(instance);
        preds[1][0]=0;
        instance[attribute]=0;
        predEval[0][0]=forest.execute(instance);
        predEval[1][0]=0;
        cSet.addValue(forest.execute(instance), series4, ""+0);
        for(int i = 1;i<instances.size();i++){
            instance = instances.get(i).clone();           
            cSet.addValue(forest.execute(instance), series2, ""+i);
            preds[0][i]=forest.execute(instance);
            preds[1][i]=i;
            instance[attribute]=0;
            cSet.addValue(forest.execute(instance), series4, ""+i);
            predEval[0][i]=forest.execute(instance);
            predEval[1][i]=i;
        }
        DefaultXYDataset dsxy= new DefaultXYDataset();
        
        double[][] d=new double[2][1];
        dsxy.addSeries("Target",d);
        dsxy.addSeries("Forecast-Train", preds);
        dsxy.addSeries("Forecast-Test", d);
        dsxy.addSeries(series4, predEval);
        return getChart(dsxy,"Attribute sensitivity");
    }
    
    
    
    public ChartPanel getChart(CategoryDataset categoryDataset, String title){        
        final JFreeChart chart = createChart(categoryDataset,title);
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new Dimension(500, 270));
        return chartPanel;
    }
    
    public ChartPanel getChart(XYDataset categoryDataset, String title){        
        final JFreeChart chart = createChart(categoryDataset,title);
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new Dimension(500, 270));
        return chartPanel;
    }

    
    private JFreeChart createChart(final XYDataset dataset, String title) {
        
        // create the chart...
        final JFreeChart chart = ChartFactory.createXYLineChart(
            title,       // chart title
            "",                    // domain axis label
            "",                   // range axis label
            dataset,                   // data
            PlotOrientation.HORIZONTAL,  // orientation
            true,                      // include legend
            false,                      // tooltips
            false                      // urls
        );
        
        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
    //    final StandardLegend legend = (StandardLegend) chart.getLegend();
     //   legend.setDisplaySeriesShapes(true);
      //  legend.setShapeScaleX(1.5);
       // legend.setShapeScaleY(1.5);
        //legend.setDisplaySeriesLines(true);

        chart.setBackgroundPaint(Color.white);

        final XYPlot plot = (XYPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.white);

        // customise the range axis...
        
      /*  final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);*/
    //*/
        // ****************************************************************************
        // * JFREECHART DEVELOPER GUIDE                                               *
        // * The JFreeChart Developer Guide, written by David Gilbert, is available   *
        // * to purchase from Object Refinery Limited:                                *
        // *                                                                          *
        // * http://www.object-refinery.com/jfreechart/guide.html                     *
        // *                                                                          *
        // * Sales are used to provide funding for the JFreeChart project - please    * 
        // * support us so that we can continue developing free software.             *
        // ****************************************************************************
        
        // customise the renderer...
        plot.setRangeCrosshairVisible(true);
        final XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer) plot.getRenderer();
    //        renderer.setDrawShapes(true);

        renderer.setSeriesStroke(
            0, new BasicStroke(
                1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f//, new float[] {10.0f, 6.0f}, 0.0f
            )
        );
        
        /*renderer.setSeriesOutlinePaint(0,Color.BLACK);
        renderer.setSeriesFillPaint(0,Color.BLACK);
        renderer.setUseOutlinePaint(true);*/
        renderer.setSeriesShape(0, ShapeUtilities.createRegularCross(1,2));
        renderer.setSeriesShapesVisible(0, true);        
        
        renderer.setSeriesStroke(
            1, new BasicStroke(
                1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesShape(1, ShapeUtilities.createRegularCross(1,2));
        renderer.setSeriesShapesVisible(1, true);
        
        renderer.setSeriesStroke(
            2, new BasicStroke(
                1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesShape(2, ShapeUtilities.createRegularCross(1,2));
        renderer.setSeriesShapesVisible(2, true);
        
        renderer.setSeriesStroke(
            3, new BasicStroke(
                1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesShape(3, ShapeUtilities.createRegularCross(1,2));
        renderer.setSeriesShapesVisible(3, true);
        
        renderer.setSeriesStroke(
            4, new BasicStroke(
                1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesShape(4, ShapeUtilities.createRegularCross(1,2));
        renderer.setSeriesShapesVisible(4, true);
        // r
       // renderer.setSeriesShape(3, ShapeUtilities.createRegularCross(2,2));
       // renderer.setSeriesShapesVisible(3, true);
        // OPTIONAL CUSTOMISATION COMPLETED.
        
        return chart;
    }
    
    
    
    /**
     * Creates a sample chart.
     * 
     * @param dataset  a dataset.
     * 
     * @return The chart.
     */
    private JFreeChart createChart(final CategoryDataset dataset, String title) {
        
        // create the chart...
        final JFreeChart chart = ChartFactory.createLineChart(
            title,       // chart title
            "Time",                    // domain axis label
            "$",                   // range axis label
            dataset,                   // data
            PlotOrientation.VERTICAL,  // orientation
            true,                      // include legend
            false,                      // tooltips
            false                      // urls
        );

        // NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
    //    final StandardLegend legend = (StandardLegend) chart.getLegend();
     //   legend.setDisplaySeriesShapes(true);
      //  legend.setShapeScaleX(1.5);
       // legend.setShapeScaleY(1.5);
        //legend.setDisplaySeriesLines(true);

        chart.setBackgroundPaint(Color.white);

        final CategoryPlot plot = (CategoryPlot) chart.getPlot();
        plot.setBackgroundPaint(Color.lightGray);
        plot.setRangeGridlinePaint(Color.white);

        // customise the range axis...
        
      /*  final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
        rangeAxis.setAutoRangeIncludesZero(true);*/
//*/
        // ****************************************************************************
        // * JFREECHART DEVELOPER GUIDE                                               *
        // * The JFreeChart Developer Guide, written by David Gilbert, is available   *
        // * to purchase from Object Refinery Limited:                                *
        // *                                                                          *
        // * http://www.object-refinery.com/jfreechart/guide.html                     *
        // *                                                                          *
        // * Sales are used to provide funding for the JFreeChart project - please    * 
        // * support us so that we can continue developing free software.             *
        // ****************************************************************************
        
        // customise the renderer...
        final LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
//        renderer.setDrawShapes(true);

        renderer.setSeriesStroke(
            0, new BasicStroke(
                2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f//, new float[] {10.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesStroke(
            1, new BasicStroke(
                2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesStroke(
            2, new BasicStroke(
                2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        renderer.setSeriesStroke(
            3, new BasicStroke(
                2.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                1.0f, new float[] {6.0f, 6.0f}, 0.0f
            )
        );
        // OPTIONAL CUSTOMISATION COMPLETED.
        
        return chart;
    }
    
    /**
     * Starting point for the demonstration application.
     *
     * @param args  ignored.
     */
    public static void main(final String[] args) {
          ArffReader ar = new ArffReader("Streetfriends7-NoStamp.arff");
         // ArffReader ar = new ArffReader("reg-auto_price.arff");
        //  ArffReader ar = new ArffReader("reg-machine_cpu.arff");
        //  ArffReader ar = new ArffReader("reg-veteran.arff");
        ar.loadData();
        Dataset dataset = new Dataset(ar.getInstances(),ar.getAttributes());
     //   final LineChartFactory demo = new LineChartFactory(dataset);
     //   JFrame frame = new JFrame();
     //   frame.getContentPane().add(demo.getChart(dataset), BorderLayout.CENTER);
     //   frame.pack();
    //    frame.setVisible(true);
      //  RefineryUtilities.centerFrameOnScreen(frame);
        

    }

}
